﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CodonSegDP
{
    public class BoudarySearcher
    {
        String Text=String.Empty;
        int minSegmentSize = 2;
        private int codonSize = 3;
        public BoudarySearcher(String _Text, int _minSegmentSize, int _codonSize = 3)
        {
            Text = _Text;
            minSegmentSize = _minSegmentSize;
            codonSize = _codonSize;
            leftSegment = new Segment(Text, codonSize, minSegmentSize);
            rightSegment = new Segment(Text, codonSize, minSegmentSize);
            costSegment = new double[Text.Length/codonSize];
            tmpArchreTriplets = new String[Text.Length / codonSize];
            windowSize = (minSegmentSize * 2) * codonSize;
        }
        public int curPostion=0;
        public double[] costSegment;
        String[] tmpArchreTriplets;
        Dictionary<double, int> dict = new Dictionary<double, int>();
        public int maxCostSegment = 0;
        bool foundNewBoundary = false;
        private Segment leftSegment;
        private Segment rightSegment;
        int windowSize;
        int costSegmentIndx = 0;
        public int GetPositionAfterFoundedMaxCostSegment()
        {
            return dict[costSegment[maxCostSegment]]; 
        }
        public String GetArcheTripletAfterFoundedMaxCostSegment()
        {
            return tmpArchreTriplets[maxCostSegment]; 
        }
        public void SearchBoundary(int curPostion)
        {


           int lastMaxCostSegment = 0;
           int i;

           leftSegment.ZeroSegNuclDistribution();
           rightSegment.ZeroSegNuclDistribution();
           dict = new Dictionary<double, int>();
           ZeroArcheTripletsStrings(tmpArchreTriplets, ref costSegmentIndx);
           ZeroCosegment(costSegment, ref costSegmentIndx);
           costSegmentIndx = 0;
           

            curPostion = leftSegment.AddTriplets(curPostion, minSegmentSize); //Add minsegSize for left matrix
            rightSegment.AddTriplets(curPostion, minSegmentSize);//Add minsegSize for right matrix

            costSegment[costSegmentIndx] = leftSegment.EvaluateCostFunction() + rightSegment.EvaluateCostFunction(); //eval costFunc (left+right)
            tmpArchreTriplets[costSegmentIndx] = leftSegment.ArcheCodonName;    //add temp ArcheCodon Name to tmpArray
            dict[costSegment[costSegmentIndx]] = curPostion;            //store the position costFunc -> position
            costSegmentIndx++;

            do
            {  //do while not found new real boundary

                i = 1;
                while (i < minSegmentSize && (curPostion + windowSize) < Text.Length)
                {
                    leftSegment.AddTripletToSegment(Text.Substring(curPostion, codonSize)); // add one triplet from right segment
                    rightSegment.RemoveTripletFromSegment(Text.Substring(curPostion, codonSize));//remove first triplet from right segment

                    rightSegment.AddTripletToSegment(Text.Substring(curPostion + minSegmentSize * codonSize, codonSize));  //add one triplet from next
                    curPostion += codonSize;

                    i++;
                    costSegment[costSegmentIndx] = leftSegment.EvaluateCostFunction() + rightSegment.EvaluateCostFunction(); //eval costFunc (left+right)
                    tmpArchreTriplets[costSegmentIndx] = leftSegment.ArcheCodonName;    //add temp ArcheCodon Name to tmpArray
                    dict[costSegment[costSegmentIndx]] = curPostion;            //store the position costFunc -> position
                    costSegmentIndx++;
                }
                maxCostSegment = FindMaxCostSegment(costSegment, ref costSegmentIndx);

                if (maxCostSegment != lastMaxCostSegment)
                { //if we find boundary better than first one

                    lastMaxCostSegment = maxCostSegment;

                    //for all triplets we add to segment we need to remove them
                    int difference =((curPostion- dict[costSegment[lastMaxCostSegment]])/codonSize);
                    for (; difference > 0; difference--)
                    {
                        leftSegment.RemoveTripletFromSegment(Text.Substring(curPostion - codonSize*difference, codonSize));
                    }
                    
                    curPostion = dict[costSegment[lastMaxCostSegment]];
                    foundNewBoundary = false;
                    i = 0;

                    rightSegment.ZeroSegNuclDistribution();
                    rightSegment.AddTriplets(curPostion, minSegmentSize);

                }
                else
                {
                    foundNewBoundary = true;
                }


            } while (foundNewBoundary != true);



        }

        private int FindMaxCostSegment(double[] costsegment, ref int costSegmentIndx)
        {
            int max_cost_index = 0;
           
            Random m_rand = new Random((int)DateTime.Now.Ticks);
            for (int i = 0; i < costSegmentIndx; ++i)
            {
                if (costsegment[i] > costsegment[max_cost_index])
                {
                    max_cost_index = i;
                }
                else if (costsegment[i] == costsegment[max_cost_index])
                { 
                     if (m_rand.Next(2) == 0)
                         max_cost_index = i;
                }
            }
            return max_cost_index;

        }
        private void ZeroCosegment(double[] costSegment, ref int costSegmentIndx)
        {
            for (int i = 0; i < costSegmentIndx; i++)
            {
                costSegment[i] = 0;
            }

        }
        private void ZeroArcheTripletsStrings(string[] tmpArchreTriplets, ref int costSegmentIndx)
        {
            for (int i = 0; i < costSegmentIndx; i++)
            {
                tmpArchreTriplets[i] = String.Empty;
            }
        }
    }
}
